/**
*
* Copyright c FOUNDER 2005 All Rights Reserved.
*
* StatementController.java
*
*/

package com.iori.common.db.dbctrl;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.torque.TorqueException;

import com.iori.common.db.DbUtil;
import com.iori.common.exception.NetFWException;



/**
 *
 * [クラス名]<br>
 *  DataAccessor一括処理クラス<br><br>
 * [機能概要]<br>
 *  DataAccessorを保持し、１トランザクションで全て実行するクラス。<br><br>
 * [変更履歴]<br>
 *  2005/07/30 ver1.00 新規作成 zhanjc<br>
 *  <br>
 *
 * @see jp.co.pia.bety.front.common.db.dbctrl.DataAccessor
 *
 * @author zhanjc
 * @version 1.00
 */
public class StatementController {
	/**
	 * コネクション数
	 */
	private int count = 0; //temp
	/**
	 * ログ出力用のインスタンス生成。
	 */
	protected static Log logger = LogFactory.getLog(StatementController.class);
	/**
	 * DataAccessorのリスト。
	 */
	private Vector dataAccessorList = new Vector();
	/**
	 * データベース名とコネクションのマップ。
	 */
	private Hashtable dbList = new Hashtable();

	/**
	 * コンストラクタ。（なにもしない）
	 */
	public StatementController() {
	}

	/**
	 * 引数のIAccessorをdataAccessorListに登録する。
	 *
	 * @param ia IAccessor
	 */
	public StatementController(IAccessor ia) {
		add(ia);
	}

	/**
	 * java.lang.Object.finalize()のオーバーライド。<br>
	 * ロールバック可能なトランザクションをロールバックし、クローズ処理を行う。
	 */
	protected void finalize() {
		if (count > 0) {
			rollback();
		}
		if (count != 0) { //temp
			logger.debug("DB ERROR, CONNECTION COUNT ！＝　0");
		}
	}

	/**
	 * addメソッドで登録されたDataAccessorを１トランザクションで実行する。<br>
	 * エラーになった場合は、ロールバックし、クローズ処理を行う。
	 *
	 * @exception	SQLException SQLのエラー
	 * @exception	NetFWException SQL以外のエラーをラップ
	 */
	public void run() throws SQLException {
		try {
			logger.debug("Running statement (" + this.dataAccessorList.size() + ")");
			Connection conn;
			for (Enumeration e = this.dataAccessorList.elements(); e.hasMoreElements();) {
				IAccessor ia = (IAccessor) e.nextElement();
				conn = getConnection(ia);
				ia.executeStatement(conn);
			}
			commit();
			return;
		}catch (Exception ex) {
			rollback();
			throw new SQLException(ex.getMessage());
		} finally {
		}
	}

	/**
	 * IAccessorのコネクションが既にコネクションマップ存在するかチェックし、
	 * 存在しない場合はコネクションマップにコネクションを追加する。
	 *
	 * @param ia IAccessor
	 *
	 * @return Connection データベースへのコネクション
	 *
	 * @exception TorqueException トランザクション開始時エラー
	 */
	private Connection getConnection(IAccessor ia) throws TorqueException, SQLException {

		if (ia.getDestination() == null)
			return null;
		String dbname = ia.getDestination();
		Connection conn;
		for (Enumeration e = this.dbList.keys(); e.hasMoreElements();) {
			String key = (String) (e.nextElement());
			if (key.equals(dbname)) {
				logger.debug("getConnection existing dbname:" + dbname);
				return (Connection) (this.dbList.get(key));
			}
		}
		conn = DbUtil.begin(dbname);
		if (ia instanceof DataAccessor) {
			conn = ((DataAccessor) ia).setSchemaForConnection(conn);
		}
		this.dbList.put(dbname, conn);
		count++; //temp
		logger.debug("getConnection new dbname:" + dbname);
		return conn;
	}

	/**
	 * 単一トランザクションで処理するIAccessorを追加する。
	 *
	 * @param ia IAccessor
	 *
	 * @return boolean true (Collection.add の汎用規約通り)
	 */
	public boolean add(IAccessor ia) {
		return this.dataAccessorList.add(ia);
	}

	/**
	 * 単一トランザクションで処理するIAccessorをリストから削除する。
	 *
	 * @param index リストから削除するIAccessorのインデックス
	 */
	public void remove(int index) {
		this.dataAccessorList.remove(index);
		logger.debug("remove(" + index + ")");
	}

	/**
	 * 単一トランザクションで処理するIAccessorのリストを取得する。
	 */
	public List getStatementList() {
		return this.dataAccessorList;
	}

	/**
	 * コミットを発行する。
	 *
	 * @exception TorqueException コミット時エラー
	 */
	private void commit() throws TorqueException, SQLException {
		Connection conn;
		for (Enumeration e = this.dbList.keys(); e.hasMoreElements();) {
			String key = (String) (e.nextElement());
			conn = (Connection) (this.dbList.get(key));
			logger.debug("commit:" + key);
			DbUtil.commit(conn);
			count--; //temp
		}
	}
	/**
	 * ロールバックを発行する。
	 */
	private void rollback() {
		Connection conn;
		for (Enumeration e = this.dbList.keys(); e.hasMoreElements();) {
			String key = (String) (e.nextElement());
			conn = (Connection) (this.dbList.get(key));
			logger.debug("rollback:" + key);
			DbUtil.safeRollback(conn);
			count--; //temp
		}
	}

	/**
	 * トランザクションの終了処理。<br>
	 * コネクションのクローズと、IAccessorリストのクリアを行う。
	 */
	private void close() {
		Connection conn;
		for (Enumeration e = this.dbList.keys(); e.hasMoreElements();) {
			String key = (String) (e.nextElement());
			conn = (Connection) (this.dbList.get(key));
			logger.debug("close:" + key);
			try {
				if (!conn.isClosed()) {
					DbUtil.closeConnection(conn);
					count--; //temp
				}
			} catch (SQLException ex) {
			}
		}
		dbList.clear();
	}

	/**
	 * DataAccessorのリストを取得する。
	 */
	public Vector getDataAccessorList() {
		return dataAccessorList;
	}
}
